package com.tiancheng.trade.merchant.configuration;


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.module.SimpleModule;

import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class BeanConfiguration {
    /**
     * 配置该 bean 可以在 @Configuration 注解的类里面使用 @Value 注解
     */
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    /**
     * 接口序列化与反序列化配置
     */
    @Bean
    @Primary
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        // 反序列化时如果多了其他属性不抛异常
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现特殊字符和转义符
        objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

        SimpleModule simpleModule = new SimpleModule();

        // yyyy-MM-dd 与 LocalDate 自动序列化与反序列化
        simpleModule.addDeserializer(LocalDate.class, JsonLocalDateFormatter.buildDeserializer());
        simpleModule.addSerializer(LocalDate.class, JsonLocalDateFormatter.buildSerializer());
        // yyyy-MM-dd HH:mm:ss 与 LocalDateTime 自动序列化与反序列化
        simpleModule.addDeserializer(LocalDateTime.class, JsonLocalDateTimeFormatter.buildDeserializer());
        simpleModule.addSerializer(LocalDateTime.class, JsonLocalDateTimeFormatter.buildSerializer());

        simpleModule.addDeserializer(Long.class, new LongJsonDeserializer());
        simpleModule.addSerializer(Long.class, new LongJsonSerializer());
        // 注册自定义反序列化, 适用于json传递参数
        objectMapper.registerModule(simpleModule);
        // 驼峰统一返回下划线
        //objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        return objectMapper;
    }

//    @Bean
//    public PaginationInterceptor paginationInterceptor() {
//        PaginationInterceptor page = new PaginationInterceptor();
//        // 设置最大单页限制数量，默认 500 条，-1 不受限制
//        page.setLimit(-1);
//        // 开启 count 的 join 优化,只针对部分 left join
//        page.setCountSqlParser(new JsqlParserCountOptimize(true));
//        return page;
//    }

    /**
     * 日志线程池配置
     *
     * @return {@link Executor}
     */
    @Bean
    public Executor logExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 配置核心线程数
        executor.setCorePoolSize(5);
        // 配置最大线程数
        executor.setMaxPoolSize(5);
        // 配置队列大小
        executor.setQueueCapacity(99999);
        // 配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-log-service-");

        // CallerRunsPolicy：超出最大线程数后的任务将进行缓存队列等待，缓存队列所有任务输送给执行队列完毕清空后，新任务进入缓存队列
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 执行初始化
        executor.initialize();
        return executor;
    }

    /**
     * 本地缓存配置
     *
     * @param redisConnectionFactory {@link RedisConnectionFactory}
     * @return {@link CacheManager}
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 设置缓存有效期两小时
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(2));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(redisCacheConfiguration).build();
    }
}
